package org.apache.camel.component.cmis;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.camel.Exchange;
import org.apache.camel.TypeConverter;
import org.apache.camel.impl.DefaultProducer;
import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CmisProducer extends DefaultProducer {
	
	private static final transient Logger	LOG	= LoggerFactory.getLogger(CmisProducer.class);
	
	public CmisProducer(CmisEndpoint cmisEndpoint) {
		super(cmisEndpoint);
	}
	
	public void process(Exchange exchange) throws Exception {
		Session session = openSession();
		
		Folder base = findOrCreateFolder(session.getRootFolder(),
				getCmisEndpoint().getPath());
		
		Document document = null;
		LOG.info("Document name : {}", getDocumentName(exchange));
		LOG.info("Document type : {}", getType(exchange));
		
		// properties
		// (minimal set: name and object type id)
		Map<String, Object> properties = new HashMap<String, Object>();
		properties.put(PropertyIds.OBJECT_TYPE_ID, getType(exchange));
		properties.put(PropertyIds.NAME, getDocumentName(exchange));
		
		TypeConverter converter = exchange.getContext().getTypeConverter();
		for (String key : exchange.getProperties().keySet()) {
			LOG.debug("Key : " + key + "value : " + exchange.getProperty(key));
			// if (key.matches(""))
			if (key.contains(":"))
				properties.put(key, converter.convertTo(Object.class, exchange,
						exchange.getProperty(key)));
		}
		InputStream inputStream = exchange.getIn().getBody(InputStream.class);
		ContentStream contentStream = converter.convertTo(ContentStream.class, exchange,
				inputStream);
		document = base.createDocument(properties, contentStream, VersioningState.NONE);
		LOG.info("Document created with id : {}", document.getId());
		exchange.getOut().setBody(document.getId());
	}
	
	private String getDocumentName(Exchange exchange) {
		if (exchange.getProperty(CmisConstants.CMIS_DOCUMENT_NAME) != null) {
			return exchange.getProperty(CmisConstants.CMIS_DOCUMENT_NAME,
					String.class);
		}
		return exchange.getExchangeId();
	}
	
	private String getType(Exchange exchange) {
		if (exchange.getProperty(CmisConstants.CMIS_DOCUMENT_TYPE) != null) {
			return exchange.getProperty(CmisConstants.CMIS_DOCUMENT_TYPE,
					String.class);
		}
		return CmisConstants.CMIS_DEFAULT_DOCUMENT_TYPE;
	}
	
	private Folder findOrCreateFolder(Folder parent, String path)
	{
		LOG.debug("Parent: {}", parent.getName());
		LOG.debug("Path {}", path);
		Folder result = parent;
		for (String component : path.split("/")) {
			LOG.debug("Component {}", component);
			if (component.length() > 0) {
				Folder componentFolder = findSubFolderByName(result, component);
				if (componentFolder == null) {
					// properties
					// (minimal set: name and object type id)
					Map<String, Object> properties = new HashMap<String, Object>();
					properties.put(PropertyIds.OBJECT_TYPE_ID, CmisConstants.CMIS_DEFAULT_FOLDER_TYPE);
					properties.put(PropertyIds.NAME, component);
					// create the folder
					result = result.createFolder(properties);
					LOG.info("Folder {} created", component);
				} else
					result = componentFolder;
			}
		}
		return result;
	}
	
	private Folder findSubFolderByName(Folder parentFolder, String folderName) {
		LOG.debug("Parent folder name : {}", parentFolder.getName());
		for (CmisObject o : parentFolder.getChildren()) {
			if (o instanceof Folder && folderName.equals(o.getName())) {
				return (Folder) o;
			}
		}
		return null;
	}
	
	protected Session openSession() {
		return getCmisEndpoint().getRepository().createSession();
	}
	
	private CmisEndpoint getCmisEndpoint() {
		CmisEndpoint endpoint = (CmisEndpoint) getEndpoint();
		return endpoint;
	}
}
